// CompilerImpl.java
// Mac Radigan
// $Id: CompilerImpl.groovy 40 2011-10-23 09:01:42Z mac.radigan $
package org.radigan.xom.impl

import org.radigan.xsp.TemplateUtilities
import org.radigan.xom.service.Compiler
import org.radigan.xom.service.Object
import org.radigan.xom.service.AstNode
import org.radigan.xom.service.XomException
import groovy.lang.GroovyClassLoader
import java.net.URI

public class CompilerImpl implements Compiler {
  private static final String ANON_PREFIX = "#AnonType_"
  private TemplateUtilities templateUtilities = null
  private GroovyClassLoader groovyClassLoader = null
  private static final String CLASS_TEMPLATE = 'public class ${className} extends ${baseClass} { }'
  public ComplilerImpl() {
    initialize()
  }
  private void initialize() {
    templateUtilities = TemplateUtilities.getInstance()
    groovyClassLoader = new GroovyClassLoader()
  }
  public org.radigan.xom.service.Object compile(AstNode astNode) {
    return createObject(astNode)
  }
  private java.lang.Object createObject(AstNode astNode) {
    def java.lang.Object newObject = null
    switch(astNode.getType()) {
      case ["string"]:
        newObject = astNode.getStringValue()
        break
      case ["decimal"]:
        newObject = astNode.getDoubleValue()
        break
      case ["integer", "positiveInteger"]:
        newObject = astNode.getIntegerValue()
        break
      default:
        if(astNode.getType().startsWith(ANON_PREFIX)) {
          def newClass = createClass(astNode.getType(), "org.radigan.xom.impl.ObjectImpl")
          newObject = newClass.newInstance()
          for(AstNode childNode : astNode.children()) {
            newObject.metaClass."${childNode.getName()}" = createObject(childNode)
          }
        } else {
          def newClass = createClass(astNode.getType(), "org.radigan.xom.impl.ObjectImpl")
          newObject = newClass.newInstance()
          for(AstNode childNode : astNode.children()) {
            newObject.metaClass."${childNode.getName()}" = createObject(childNode)
          }
        }
        break
    }
    return newObject
  }
  private Class createClass(String className, String baseClass) {
    def templateUtilities = TemplateUtilities.getInstance()
    def groovyClassLoader = new GroovyClassLoader()
    def classNameAdjusted = className.replaceAll(ANON_PREFIX, "")
    def bindings = ['className':classNameAdjusted, 'baseClass':baseClass]
    def classSource = templateUtilities.xsp(CLASS_TEMPLATE, bindings)
    def newClass = groovyClassLoader.parseClass(classSource)
    return newClass
  }
}

// *EOF*
